// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ChartHelper.cs" company="Concept Architecture">
//   (c) 2010 Muhammad Umer Farooq
// </copyright>
// <summary>
//   Defines the <seealso cref="Hisaab.Windows.Common.ChartHelper" /> type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Hisaab.Client.Common.Helpers
{
    using System;
    using System.Collections;
    using System.Windows;
    using System.Windows.Controls.DataVisualization.Charting;
    using System.Windows.Data;

    /// <summary>
    /// Defines the <seealso cref="ChartHelper"/> type.
    /// </summary>
    public class ChartHelper
    {
        #region Attached Properties

        /// <summary>
        /// Series source attached property
        /// </summary>
        public static readonly DependencyProperty SeriesSourceProperty =
                DependencyProperty.RegisterAttached("SeriesSource", typeof(IEnumerable), typeof(ChartHelper), new PropertyMetadata(SeriesSourceChanged));

        /// <summary>
        /// Dependent Value Binding attached property
        /// </summary>
        public static readonly DependencyProperty DependentValueBindingProperty =
            DependencyProperty.RegisterAttached("DependentValueBinding", typeof(string), typeof(ChartHelper), null);

        /// <summary>
        /// Independent value binding attached property
        /// </summary>
        public static readonly DependencyProperty IndependentValueBindingProperty =
            DependencyProperty.RegisterAttached("IndependentValueBinding", typeof(string), typeof(ChartHelper), null);

        /// <summary>
        /// Title attached property
        /// </summary>
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.RegisterAttached("Title", typeof(string), typeof(ChartHelper), null);

        /// <summary>
        /// Series type attached property
        /// </summary>
        public static readonly DependencyProperty SeriesTypeProperty =
            DependencyProperty.RegisterAttached("SeriesType", typeof(SeriesType), typeof(ChartHelper), new PropertyMetadata(SeriesType.Bar));

        /// <summary>
        /// Series style attached property
        /// </summary>
        public static readonly DependencyProperty SeriesStyleProperty =
            DependencyProperty.RegisterAttached("SeriesStyle", typeof(Style), typeof(ChartHelper), null);

        #endregion Attached Properties

        #region SeriesSource

        /// <summary>
        /// Gets the series source.
        /// </summary>
        /// <param name="dependencyObject">The dependencyObject.</param>
        /// <returns>Series source</returns>
        public static IEnumerable GetSeriesSource(DependencyObject dependencyObject)
        {
            return (IEnumerable)dependencyObject.GetValue(SeriesSourceProperty);
        }

        /// <summary>
        /// Sets the series source.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <param name="value">The value.</param>
        public static void SetSeriesSource(DependencyObject dependencyObject, IEnumerable value)
        {
            dependencyObject.SetValue(SeriesSourceProperty, value);
        }

        #endregion SeriesSource

        #region DependentValueBinding

        /// <summary>
        /// Gets the dependent value binding.
        /// </summary>
        /// <param name="dependencyObject">The dependency object</param>
        /// <returns>Dependency value</returns>
        public static string GetDependentValueBinding(DependencyObject dependencyObject)
        {
            return (string)dependencyObject.GetValue(DependentValueBindingProperty);
        }

        /// <summary>
        /// Sets the dependent value binding.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <param name="value">The value.</param>
        public static void SetDependentValueBinding(DependencyObject dependencyObject, string value)
        {
            dependencyObject.SetValue(DependentValueBindingProperty, value);
        }

        #endregion DependentValueBinding

        #region IndependentValueBinding

        /// <summary>
        /// Gets the independent value binding.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <returns>Independent value</returns>
        public static string GetIndependentValueBinding(DependencyObject dependencyObject)
        {
            return (string)dependencyObject.GetValue(IndependentValueBindingProperty);
        }

        /// <summary>
        /// Sets the independent value binding.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <param name="value">The value.</param>
        public static void SetIndependentValueBinding(DependencyObject dependencyObject, string value)
        {
            dependencyObject.SetValue(IndependentValueBindingProperty, value);
        }

        #endregion IndependentValueBinding

        #region Title

        /// <summary>
        /// Gets the title.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <returns>Title value</returns>
        public static string GetTitle(DependencyObject dependencyObject)
        {
            return (string)dependencyObject.GetValue(TitleProperty);
        }

        /// <summary>
        /// Sets the title.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <param name="value">The value.</param>
        public static void SetTitle(DependencyObject dependencyObject, string value)
        {
            dependencyObject.SetValue(TitleProperty, value);
        }

        #endregion Title

        #region SeriesType

        /// <summary>
        /// Gets the type of the series.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <returns>Series type value</returns>
        public static SeriesType GetSeriesType(DependencyObject dependencyObject)
        {
            return (SeriesType)dependencyObject.GetValue(SeriesTypeProperty);
        }

        /// <summary>
        /// Sets the type of the series.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <param name="value">The value.</param>
        public static void SetSeriesType(DependencyObject dependencyObject, SeriesType value)
        {
            dependencyObject.SetValue(SeriesTypeProperty, value);
        }

        #endregion SeriesType

        #region SeriesStyle

        /// <summary>
        /// Gets the series style.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <returns>Series style value</returns>
        public static Style GetSeriesStyle(DependencyObject dependencyObject)
        {
            return (Style)dependencyObject.GetValue(SeriesStyleProperty);
        }

        /// <summary>
        /// Sets the series style.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <param name="value">The value.</param>
        public static void SetSeriesStyle(DependencyObject dependencyObject, Style value)
        {
            dependencyObject.SetValue(SeriesStyleProperty, value);
        }

        #endregion SeriesStyle

        /// <summary>
        /// Serieses the source changed.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void SeriesSourceChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            if (!(dependencyObject is Chart))
            {
                throw new Exception("Series attached property only works on a Chart type");
            }

            var chart = dependencyObject as Chart;

            chart.Series.Clear();

            var chartSeriesSource = e.NewValue as IEnumerable;

            if (chartSeriesSource == null)
            {
                throw new Exception("The SeriesSource does not support IEnumerable");
            }

            foreach (var dataSource in chartSeriesSource)
            {
                DataPointSeries series;

                var seriesType = GetSeriesType(chart);

                switch (seriesType)
                {
                    case SeriesType.Line:
                        series = new LineSeries();
                        break;
                    case SeriesType.Bar:
                        series = new BarSeries();
                        break;
                    case SeriesType.Column:
                        series = new ColumnSeries();
                        break;
                    case SeriesType.Pie:
                        series = new PieSeries();
                        break;
                    case SeriesType.Scatter:
                        series = new ScatterSeries();
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }

                var seriesStyle = GetSeriesStyle(chart);
                series.Style = seriesStyle;

                var titleBindingName = GetTitle(chart);

                if (!string.IsNullOrEmpty(titleBindingName))
                {
                    var titleBinding = new Binding(titleBindingName)
                    {
                        Source = series.Title,
                        Mode = BindingMode.TwoWay
                    };

                    series.SetBinding(Series.TitleProperty, titleBinding);
                }

                series.DependentValueBinding = new Binding(GetDependentValueBinding(chart));
                series.IndependentValueBinding = new Binding(GetIndependentValueBinding(chart));

                series.ItemsSource = dataSource as IEnumerable;

                chart.Series.Add(series);
            }
        }
    }
}